#ifndef NEW_TYPE_H
#define NEW_TYPE_H

#include <stdexcept>
#include <ostream>
#include <limits>



struct NewType
{
private:
    long double _coefficient;

public:
    explicit NewType(long double coef = 0) : _coefficient(coef)
    {
    }

    bool operator> (NewType r) const
    {
        return _coefficient> r._coefficient;
    }

    NewType & operator+= (NewType r)
    {
        _coefficient += r._coefficient;
        return *this;
    }

    NewType & operator-= (NewType r)
    {
        _coefficient -= r._coefficient;
        return *this;
    }

    NewType const operator- (NewType r) const
    {
        return NewType(*this) -= r;
    }

    NewType const operator- () const
    {
        return NewType(-_coefficient);
    }

    NewType & operator/= (NewType r)
    {
        _coefficient /= r._coefficient;
        return *this;
    }

    NewType const abs()
    {
        return NewType(std::abs(_coefficient));
    }
private:
    NewType & operator*= (NewType r)
    {
        _coefficient *= r._coefficient;
        return *this;
    }
public:
    NewType & operator*= (double r)
    {
        _coefficient *= r;
        return *this;
    }
    NewType const operator* (NewType r) const
    {
        return NewType(*this) *= r;
    }
    
    friend std::ostream & operator<< (std::ostream & stream, NewType r);
};

std::ostream & operator<< (std::ostream & stream, NewType r)
{
    return stream << r._coefficient;
}

template<>
struct MatrixElementTrait<NewType>
{
    enum 
    {
        IsInvertable = true
    };
    static NewType const Precision;
    static NewType Abs(NewType val) { return val.abs(); }
    static NewType GetRandom() { return NewType(std::rand() % 100 + 1); }
};

NewType const MatrixElementTrait<NewType>::Precision = NewType(1e-10);

#endif // NEW_TYPE_H